//
//  WatchValue.swift
//  ExWatch
//
//  Created by 王渊鸥 on 2018/10/11.
//  Copyright © 2018年 王渊鸥. All rights reserved.
//

import Foundation
import ExMedia

public class WatchValue <T> where T:Any {
    public typealias ValueType = T
    public var value:ValueType {
        didSet {
            watches.forEach { (watch) in
                watch.1(value)
            }
            
            if let storageKey = storageKey {
                if let color = value as? UIColor {
                    let text = color.hex6
                    UserDefaults.standard.set(text, forKey: storageKey)
                } else if let font = value as? UIFont {
                    let text = "\(font.fontName)%\(font.pointSize)"
                    UserDefaults.standard.set(text, forKey: storageKey)
                } else if let rect = value as? CGRect {
                    let text = "\(rect.minX)%\(rect.minY)%\(rect.width)%\(rect.height)"
                    UserDefaults.standard.set(text, forKey: storageKey)
                } else if let size = value as? CGSize {
                    let text = "\(size.width)%\(size.height)"
                    UserDefaults.standard.set(text, forKey: storageKey)
                } else if let point = value as? CGPoint {
                    let text = "\(point.x)%\(point.y)"
                    UserDefaults.standard.set(text, forKey: storageKey)
                } else {
                    UserDefaults.standard.set(value, forKey: storageKey)
                }
                
                UserDefaults.standard.synchronize()
            }
        }
    }
    
    private var storageKey:String?
    
    public typealias OnChangeValue = (ValueType)->()
    public var watches:[(String?, OnChangeValue)] = []
    
    public init(_ value:ValueType) {
        self.value = value
    }
    
    public init(storageKey:String?, default:ValueType) {
        if let storageKey = storageKey {
            self.storageKey = storageKey
            
            if let value = UserDefaults.standard.value(forKey: storageKey) {
                if `default` is UIFont {
                    if let text = value as? String {
                        if let (name, size) = text.apart2("%") {
                            self.value = UIFont(name: name, size: CGFloat(Float(size) ?? 40)) as! ValueType
                            return
                        }
                    }
                } else if `default` is UIColor {
                    if let text = value as? String {
                        self.value = UIColor(hex: text) as! ValueType
                        return
                    }
                } else if `default` is CGRect {
                    if let text = value as? String {
                        if let (x, y, w, h) = text.apart4("%") {
                            self.value = CGRect(x: Double(x) ?? 0, y: Double(y) ?? 0, width: Double(w) ?? 0, height: Double(h) ?? 0) as! ValueType
                            return
                        }
                    }
                } else if `default` is CGPoint {
                    if let text = value as? String {
                        if let (x, y) = text.apart2("%") {
                            self.value = CGPoint(x: Double(x) ?? 0, y: Double(y) ?? 0) as! ValueType
                            return
                        }
                    }
                } else if `default` is CGSize {
                    if let text = value as? String {
                        if let (w, h) = text.apart2("%") {
                            self.value = CGSize(width: Double(w) ?? 0, height: Double(h) ?? 0) as! ValueType
                            return
                        }
                    }
                }
                
                self.value = value as! ValueType
                return
            }
        }
        
        self.value = `default`
    }
    
    public func add(_ watch:@escaping OnChangeValue, key:String?) {
        watches.append((key, watch))
    }
    
    public func removeWatch(byKey:String?) {
        watches.removeAll { (watch) -> Bool in
            return watch.0 == byKey
        }
    }
    
    public func removeAll() {
        watches.removeAll()
    }
}
